﻿/*
 * Copyright © 2020, Wuxi Safover Intelligent Technology Co., Ltd. All rights reserved.
 * 
 * 无锡安永智能科技有限公司版权所有，未经许可，不得用于商业用途
 * 
 * Visit: https://www.safover.com/ 
 */

using SafoverWpfFw;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Safover.LidarCollector.Models;
using Safover.LidarCollector.Config;
using Safover.Lidar.DataContract;

namespace Safover.LidarCollector.ViewModel
{
    public class LidarWorkModeConfigViewModel : BaseViewModel
    {
        public static LidarWorkModeConfigViewModel Instance = new LidarWorkModeConfigViewModel();

        public LidarWorkMode LidarWorkMode { get; set; }

        public ICommand SaveCommand { get; set; }

        public ICommand AddStepCommand { get; set; }

        public ICommand RemoveStepCommand { get; set; }

        public ICommand AddVerticalBlindSectorCommand { get; set; }
        public ICommand RemoveVerticalBlindSectorCommand { get; set; }
        public ICommand AddHorizontalBlindSectorCommand { get; set; }
        public ICommand RemoveHorizontalBlindSectorCommand { get; set; }


        public TimeSpan PeriodScanEndDelayDuration { get; set; }

        public TimeSpan SingleScanEndDelayDuration { get; set; }



        public float FixedVertialAngle { get; set; }

        public float FixedHorizontalAngle { get; set; }


        public float UnderwayVertialAngle { get; set; }

        public float UnderwayHorizontalAngle { get; set; }


        public float HorizontalStartAngle { get; set; }

        public float HorizontalRangeAngle { get; set; }

        public float HorizontalStepAngle { get; set; }

        public float HorizontalScanFixedVerticalAngle { get; set; }


        public float VerticalStartAngle { get; set; }

        public float VerticalRangeAngle { get; set; }

        public float VerticalStepAngle { get; set; }

        public float VerticalScanFixedHorizontalAngle { get; set; }

        public ObservableCollection<StepScanViewModel> MultiScanSteps { get; set; } = new ObservableCollection<StepScanViewModel>();

        public ObservableCollection<BlindSectorViewModel> VerticalBlindSectorViewModels { get; set; } = new ObservableCollection<BlindSectorViewModel>();

        public ObservableCollection<BlindSectorViewModel> HorizontalBlindSectorViewModels { get; set; } = new ObservableCollection<BlindSectorViewModel>();

        LidarWorkModeConfigViewModel()
        {
            LidarConfig config = RuntimeConfigManager.Instance.LidarConfig;
            LidarWorkMode = config.LidarWorkMode;

            PeriodScanEndDelayDuration = config.PeriodScanEndDelayDuration;
            SingleScanEndDelayDuration = config.SingleScanEndDelayDuration;

            FixedVertialAngle = config.FixedVertialAngle;
            FixedHorizontalAngle = config.FixedHorizontalAngle;

            UnderwayVertialAngle = config.UnderwayVertialAngle;
            UnderwayHorizontalAngle = config.UnderwayHorizontalAngle;

            HorizontalStartAngle = config.HorizontalStartAngle;
            HorizontalRangeAngle = config.HorizontalRangeAngle;
            HorizontalStepAngle = config.HorizontalStepAngle;
            HorizontalScanFixedVerticalAngle = config.HorizontalScanFixedVerticalAngle;

            VerticalStartAngle = config.VerticalStartAngle;
            VerticalRangeAngle = config.VerticalRangeAngle;
            VerticalStepAngle = config.VerticalStepAngle;
            VerticalScanFixedHorizontalAngle = config.VerticalScanFixedHorizontalAngle;

            foreach (var step in config.MultiScanSteps)
            {
                switch (step.LidarWorkMode)
                {
                    case LidarWorkMode.Fixed:
                        MultiScanSteps.Add(new FixedScanConfigViewModel(step as FixedDirectionScanConfig));
                        break;
                    case LidarWorkMode.Horizontal:
                        MultiScanSteps.Add(new HorizontalScanConfigViewModel(step as HorizontalScanConfig));
                        break;
                    case LidarWorkMode.Vertical:
                        MultiScanSteps.Add(new VerticalScanConfigViewModel(step as VerticalScanConfig));
                        break;
                    case LidarWorkMode.Underway:
                        MultiScanSteps.Add(new UnderwayConfigViewModel(step as UnderwayScanConfig));
                        break;
                    case LidarWorkMode.Multi:
                    default:
                        throw new InvalidOperationException($"Failed to handle [{step.LidarWorkMode}].");
                }
            }

            foreach (var blindSector in config.VerticalBlindSectorConfigs)
            {
                VerticalBlindSectorViewModels.Add(new BlindSectorViewModel(blindSector));
            }

            foreach (var blindSector in config.HorizontalBlindSectorConfigs)
            {
                HorizontalBlindSectorViewModels.Add(new BlindSectorViewModel(blindSector));
            }

            SaveCommand = new RelayCommand(Save);
            AddStepCommand = new RelayParameterizedCommand(AddStep);
            RemoveStepCommand = new RelayCommand(RemoveStep);


            AddVerticalBlindSectorCommand = new RelayCommand(AddVerticalBlindSector);
            RemoveVerticalBlindSectorCommand = new RelayCommand(RemoveVerticalBlindSector);
            AddHorizontalBlindSectorCommand = new RelayCommand(AddHorizontalBlindSector);
            RemoveHorizontalBlindSectorCommand = new RelayCommand(RemoveHorizontalBlindSector);
        }

        private void RemoveStep()
        {
            RemoveSeletected(MultiScanSteps);
        }

        private void RemoveSeletected<T>(ObservableCollection<T> collection) where T: ISelectable
        {
            var removedList = new List<T>();
            foreach (var step in collection)
            {
                if (step.IsSelected)
                {
                    removedList.Add(step);
                }
            }

            foreach (var remove in removedList)
            {
                collection.Remove(remove);
            }
        }

        private void AddStep(object scanMode)
        {
            if (!Enum.TryParse(scanMode.ToString(), out LidarWorkMode mode))
            {
                return;
            }

            StepScanViewModel step = null;
            switch (mode)
            {
                case LidarWorkMode.Fixed:
                    step = new FixedScanConfigViewModel(new FixedDirectionScanConfig
                    {
                    });
                    break;
                case LidarWorkMode.Horizontal:
                    step = new HorizontalScanConfigViewModel(new HorizontalScanConfig
                    {
                    });
                    break;
                case LidarWorkMode.Vertical:
                    step = new VerticalScanConfigViewModel(new VerticalScanConfig
                    {
                    });
                    break;
                case LidarWorkMode.Underway:
                case LidarWorkMode.Multi:
                default:
                    break;
            }

            if (step != null)
            {
                MultiScanSteps.Add(step);
            }
        }

        private float verticalBlindStartAngle = 0f;
        public float VerticalBlindStartAngle
        {
            get => verticalBlindStartAngle;
            set
            {
                if (!IsWithinRange(value, 180))
                {
                    return;
                }

                verticalBlindStartAngle = value;
                OnPropertyChanged(nameof(VerticalBlindStartAngle));
            }
        }

        private float verticalBlindAngle = 10f;
        public float VerticalBlindAngle
        {
            get => verticalBlindAngle;
            set
            {
                if (!IsWithinRange(value, 180))
                {
                    return;
                }

                verticalBlindAngle = value;
                OnPropertyChanged(nameof(VerticalBlindAngle));
            }
        }

        private float horizontalBlindStartAngle = 0f;
        public float HorizontalBlindStartAngle 
        {
            get => horizontalBlindStartAngle;
            set
            {
                if (!IsWithinRange(value, 360))
                {
                    return;
                }
                horizontalBlindStartAngle = value;
                OnPropertyChanged(nameof(HorizontalBlindStartAngle));
            }
        }

        private float horizontalBlindAngle = 10f;
        public float HorizontalBlindAngle
        {
            get => horizontalBlindAngle;
            set
            {
                if (!IsWithinRange(value, 360))
                {
                    return;
                }

                horizontalBlindAngle = value;
                OnPropertyChanged(nameof(HorizontalBlindAngle));
            }
        }

       

        private void AddVerticalBlindSector()
        {
            VerticalBlindSectorViewModels.Add(new BlindSectorViewModel(VerticalBlindStartAngle, VerticalBlindAngle));
        }

        private void RemoveVerticalBlindSector()
        {
            RemoveSeletected(VerticalBlindSectorViewModels);
        }

        private void AddHorizontalBlindSector()
        {
            HorizontalBlindSectorViewModels.Add(new BlindSectorViewModel(HorizontalBlindStartAngle, HorizontalBlindAngle));
        }

        private void RemoveHorizontalBlindSector()
        {
            RemoveSeletected(HorizontalBlindSectorViewModels);
        }

        private void Save()
        {
            var multiScanSteps = new List<SingleScanConfig>();
            foreach (var step in MultiScanSteps)
            {
                step.IsSelected = false;
                multiScanSteps.Add(step.ToConfig());
            }

            var verticalBlindSectors = new List<VerticalBlindSectorConfig>();
            foreach (var blindSector in VerticalBlindSectorViewModels)
            {
                blindSector.IsSelected = false;
                verticalBlindSectors.Add(blindSector.ToVerticalBlindSectorConfig());
            }

            var horizontalBlindSectors = new List<HorizontalBlindSectorConfig>();
            foreach (var blindSector in HorizontalBlindSectorViewModels)
            {
                blindSector.IsSelected = false;
                horizontalBlindSectors.Add(blindSector.ToHorizontalBlindSectorConfig());
            }

            var config = new LidarConfig
            {
                LidarWorkMode = LidarWorkMode,

                PeriodScanEndDelayDuration = PeriodScanEndDelayDuration,
                SingleScanEndDelayDuration = SingleScanEndDelayDuration,

                FixedVertialAngle = FixedVertialAngle,
                FixedHorizontalAngle = FixedHorizontalAngle,

                UnderwayHorizontalAngle = UnderwayHorizontalAngle,
                UnderwayVertialAngle = UnderwayVertialAngle,

                HorizontalStartAngle = HorizontalStartAngle,
                HorizontalRangeAngle = HorizontalRangeAngle,
                HorizontalStepAngle = HorizontalStepAngle,
                HorizontalScanFixedVerticalAngle = HorizontalScanFixedVerticalAngle,

                VerticalStartAngle = VerticalStartAngle,
                VerticalRangeAngle = VerticalRangeAngle,
                VerticalStepAngle = VerticalStepAngle,
                VerticalScanFixedHorizontalAngle = VerticalScanFixedHorizontalAngle,

                MultiScanSteps = multiScanSteps,
                VerticalBlindSectorConfigs = verticalBlindSectors,
                HorizontalBlindSectorConfigs = horizontalBlindSectors,
            };

            RuntimeConfigManager.Instance.Save(config);

            _ = DI.UI.ShowMessage(new MessageBoxDialogViewModel
            {
                Title = "提示",
                Message = "保存成功！"
            });
        }

        private bool IsWithinRange(float value, float range)
        {
            if (value < 0 || value > range)
            {
                return false;
            }

            if (value + VerticalBlindAngle > range)
            {
                return false;
            }

            return true;
        }
    }
}
